using System;
using System.Collections.Generic;
using System.Diagnostics;
using Firestarter.DB.Schema.BO;
using Firestarter.DB.Schema.Test.BO.TestUtils;
using Firestarter.Test.Base;
using FireStarterModeller.BO;
using FireStarterModeller.Test;
using Habanero.BO;
using Habanero.BO.ClassDefinition;
using NUnit.Framework;

namespace Firestarter.DB.Schema.Test.BO
{
    public partial class TestDBView
    {
        private readonly Dictionary<string, string> _ignoreList = new Dictionary<string, string>();

        /// <summary>
        /// Checks if the developer has put this test on the ignore list.
        /// If your application has a unique condition that is causing a
        /// generated test to fail, you would lose test repairs when this
        /// class is regenerated.
        /// Simply add the test name to the ignore list in the TestFixtureSetup
        /// of the once-off-generated part of this test class, and then
        /// reimplement the test in that class.
        /// </summary>
        private void CheckIfTestShouldBeIgnored()
        {
            string methodName = new StackTrace().GetFrame(1).GetMethod().Name;
            if (_ignoreList.ContainsKey(methodName))
            {
                Assert.Ignore("The developer has chosen to ignore this test: " + methodName +
                              ", Reason: " + _ignoreList[methodName]);
            }
        }
        
        [Test]  // Ensures that the defaults have not been tampered
        public void Test_CreateDBViewWithDefaults()
        {
            CheckIfTestShouldBeIgnored();
            //---------------Set up test pack-------------------

            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            DBView dbView = new DBView();

            //---------------Test Result -----------------------
            Assert.IsNull(dbView.DateCreated);
            Assert.IsNull(dbView.Owner);
            Assert.IsNull(dbView.TableName);
            Assert.IsNotNull(dbView.ViewID);
            Assert.IsInstanceOf(dbView.Props["ViewID"].PropertyType, dbView.ViewID);
            Assert.IsNull(dbView.DatabaseID);
//                        Assert.IsNull(dbView.TableType);
            Assert.AreEqual("DBView", dbView.TableType);
            Assert.IsNull(dbView.TableComment);
            Assert.IsNull(dbView.CreateTime);
            Assert.IsNull(dbView.UpdateTime);
            Assert.IsNotNull(dbView.PendingChangeType);
            Assert.IsInstanceOf(dbView.Props["PendingChangeType"].PropertyType, dbView.PendingChangeType);
            Assert.IsNotNull(dbView.Approved);
        }

        [Test]  // Ensures that a class can be successfully saved
        public void Test_SaveDBView()
        {
            CheckIfTestShouldBeIgnored();
            //---------------Set up test pack-------------------
            DBView dbView = TestUtilsDBView.CreateUnsavedValidDBView();

            //---------------Assert Precondition----------------
            Assert.IsTrue(dbView.Status.IsNew);
            BusinessObjectCollection<DBView> col = new BusinessObjectCollection<DBView>();
            col.LoadAll();
            Assert.AreEqual(0, col.Count);

            //---------------Execute Test ----------------------
            dbView.Save();

            //---------------Test Result -----------------------
            Assert.IsFalse(dbView.Status.IsNew);
            col.LoadAll();
            Assert.AreEqual(1, col.Count);
	    
        }
        
        [Test]  // Ensures that a saved class can be loaded
        public void Test_LoadDBView()
        {
            CheckIfTestShouldBeIgnored();
            //---------------Set up test pack-------------------
            DBView dbView = TestUtilsDBView.CreateSavedDBView();

            //---------------Execute Test ----------------------
            DBView loadedDBView = Broker.GetBusinessObject<DBView>(dbView.ID);

            //---------------Test Result -----------------------
            Assert.AreEqual(dbView.DateCreated, loadedDBView.DateCreated);
            Assert.AreEqual(dbView.Owner, loadedDBView.Owner);
            Assert.AreEqual(dbView.TableName, loadedDBView.TableName);
            Assert.AreEqual(dbView.ViewID, loadedDBView.ViewID);
            Assert.AreEqual(dbView.DatabaseID, loadedDBView.DatabaseID);
            Assert.AreEqual(dbView.TableType, loadedDBView.TableType);
            Assert.AreEqual(dbView.TableComment, loadedDBView.TableComment);
            Assert.AreEqual(dbView.CreateTime, loadedDBView.CreateTime);
            Assert.AreEqual(dbView.UpdateTime, loadedDBView.UpdateTime);
            Assert.AreEqual(dbView.PendingChangeType, loadedDBView.PendingChangeType);
            Assert.AreEqual(dbView.Approved, loadedDBView.Approved);
        }
        
        [Test]  // Ensures that a class can be deleted
        public void Test_DeleteDBView()
        {
            CheckIfTestShouldBeIgnored();
            //---------------Set up test pack-------------------
            DBView dbView = TestUtilsDBView.CreateSavedDBView();
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            dbView.MarkForDelete();
            dbView.Save();
            //---------------Test Result -----------------------
            try
            {
                Broker.GetBusinessObject<DBView>(dbView.ID);
                Assert.Fail("expected Err");
            }
            catch (BusObjDeleteConcurrencyControlException ex)
            {
                StringAssert.Contains("A Error has occured since the object you are trying to refresh has been deleted by another user", ex.Message);
                StringAssert.Contains("There are no records in the database for the Class: DBView", ex.Message);
            }
        }

        [Test]  // Ensures that updates to property values are stored and can be retrieved
        public void Test_UpdateDBView()
        {
            CheckIfTestShouldBeIgnored();
            //---------------Set up test pack-------------------
            DBView dbView = TestUtilsDBView.CreateSavedDBView();
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            object valueForDateCreated = TestUtilsShared.GetRandomDate();
            dbView.DateCreated = (System.DateTime) valueForDateCreated;
            object valueForOwner = TestUtilsShared.GetRandomString();
            dbView.Owner = (System.String) valueForOwner;
            object valueForViewName = TestUtilsShared.GetRandomString(1,255);
            dbView.TableName = (System.String) valueForViewName;
//            object valueForDatabaseID = TestUtilsDBDatabase.CreateSavedDBDatabase().DatabaseID;
//            dbView.DatabaseID = (System.Guid) valueForDatabaseID;
/*            object valueForTableType = TestUtilsShared.GetRandomString();
            dbView.TableType = (System.String) valueForTableType;*/
            object valueForTableComment = TestUtilsShared.GetRandomString();
            dbView.TableComment = (System.String) valueForTableComment;
            object valueForCreateTime = TestUtilsShared.GetRandomDate();
            dbView.CreateTime = (System.DateTime) valueForCreateTime;
            object valueForUpdateTime = TestUtilsShared.GetRandomDate();
            dbView.UpdateTime = (System.DateTime) valueForUpdateTime;

            object valueForApproved = TestUtilsShared.GetRandomBoolean();
            dbView.Approved = (System.Boolean) valueForApproved;
            dbView.Save();

            //---------------Test Result -----------------------
            BusinessObjectManager.Instance.ClearLoadedObjects();
            GC.Collect();
            TestUtilsDomain.WaitForGC();
            DBView retrievedDBView =
                Broker.GetBusinessObject<DBView>(dbView.ID);
            
            Assert.AreEqual(valueForDateCreated, retrievedDBView.DateCreated);
            Assert.AreEqual(valueForOwner, retrievedDBView.Owner);
            Assert.AreEqual(valueForViewName, retrievedDBView.TableName);
//            Assert.AreEqual(valueForDatabaseID, retrievedDBView.DatabaseID);
    //        Assert.AreEqual(valueForTableType, retrievedDBView.TableType);
            Assert.AreEqual(valueForTableComment, retrievedDBView.TableComment);
            Assert.AreEqual(valueForCreateTime, retrievedDBView.CreateTime);
            Assert.AreEqual(valueForUpdateTime, retrievedDBView.UpdateTime);
            Assert.AreEqual(valueForApproved, retrievedDBView.Approved);
        }
        
        [Test]  // Ensures that gets and sets in the code refer to the same property
        public void Test_PropertyGetters()
        {
            CheckIfTestShouldBeIgnored();
            //---------------Set up test pack-------------------
            DBView dbView = new DBView();
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            object valueForDateCreated = TestUtilsShared.GetRandomDate();
            dbView.DateCreated = (System.DateTime) valueForDateCreated;
            object valueForOwner = TestUtilsShared.GetRandomString();
            dbView.Owner = (System.String) valueForOwner;
            object valueForViewName = TestUtilsShared.GetRandomString(1,255);
            dbView.TableName = (System.String) valueForViewName;
            object valueForDatabaseID = TestUtilsDBDatabase.CreateSavedDBDatabase().DatabaseID;
            dbView.DatabaseID = (System.Guid?) valueForDatabaseID;
            object valueForTableType = TestUtilsShared.GetRandomString();
            dbView.TableType = (System.String) valueForTableType;
            object valueForTableComment = TestUtilsShared.GetRandomString();
            dbView.TableComment = (System.String) valueForTableComment;
            object valueForCreateTime = TestUtilsShared.GetRandomDate();
            dbView.CreateTime = (System.DateTime) valueForCreateTime;
            object valueForUpdateTime = TestUtilsShared.GetRandomDate();
            dbView.UpdateTime = (System.DateTime) valueForUpdateTime;

            object valueForApproved = TestUtilsShared.GetRandomBoolean();
            dbView.Approved = (System.Boolean) valueForApproved;
            
            //---------------Test Result -----------------------
            Assert.AreEqual(valueForDateCreated, dbView.DateCreated);
            Assert.AreEqual(valueForOwner, dbView.Owner);
            Assert.AreEqual(valueForViewName, dbView.TableName);
            Assert.AreEqual(valueForDatabaseID, dbView.DatabaseID);
            Assert.AreEqual(valueForTableType, dbView.TableType);
            Assert.AreEqual(valueForTableComment, dbView.TableComment);
            Assert.AreEqual(valueForCreateTime, dbView.CreateTime);
            Assert.AreEqual(valueForUpdateTime, dbView.UpdateTime);
            Assert.AreEqual(valueForApproved, dbView.Approved);
        }
        
        [Test]  // Ensures that property getters in the code point to the correct property
        public void Test_PropertyGettersUseCorrectPropertyNames()
        {
            CheckIfTestShouldBeIgnored();
            //---------------Set up test pack-------------------
            DBView dbView = new DBView();
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            object valueForDateCreated = TestUtilsShared.GetRandomDate();
            dbView.DateCreated = (System.DateTime) valueForDateCreated;
            object valueForOwner = TestUtilsShared.GetRandomString();
            dbView.Owner = (System.String) valueForOwner;
            object valueForViewName = TestUtilsShared.GetRandomString(1,255);
            dbView.TableName = (System.String) valueForViewName;
            object valueForSchemaName = TestUtilsShared.GetRandomString(1, 255);
            dbView.SchemaName = (System.String)valueForSchemaName;
            object valueForDatabaseID = TestUtilsDBDatabase.CreateSavedDBDatabase().DatabaseID;
            dbView.DatabaseID = (System.Guid?) valueForDatabaseID;
            object valueForTableType = TestUtilsShared.GetRandomString();
            dbView.TableType = (System.String) valueForTableType;
            object valueForTableComment = TestUtilsShared.GetRandomString();
            dbView.TableComment = (System.String) valueForTableComment;
            object valueForCreateTime = TestUtilsShared.GetRandomDate();
            dbView.CreateTime = (System.DateTime) valueForCreateTime;
            object valueForUpdateTime = TestUtilsShared.GetRandomDate();
            dbView.UpdateTime = (System.DateTime) valueForUpdateTime;

            object valueForApproved = TestUtilsShared.GetRandomBoolean();
            dbView.Approved = (System.Boolean) valueForApproved;
            
            //---------------Test Result -----------------------
            Assert.AreEqual(valueForDateCreated, dbView.GetPropertyValue("DateCreated"));
            Assert.AreEqual(valueForOwner, dbView.GetPropertyValue("Owner"));
            Assert.AreEqual(valueForViewName, dbView.GetPropertyValue("TableName"));
            Assert.AreEqual(valueForSchemaName, dbView.GetPropertyValue("SchemaName"));
            Assert.AreEqual(valueForDatabaseID, dbView.GetPropertyValue("DatabaseID"));
            Assert.AreEqual(valueForTableType, dbView.GetPropertyValue("TableType"));
            Assert.AreEqual(valueForTableComment, dbView.GetPropertyValue("TableComment"));
            Assert.AreEqual(valueForCreateTime, dbView.GetPropertyValue("CreateTime"));
            Assert.AreEqual(valueForUpdateTime, dbView.GetPropertyValue("UpdateTime"));
            Assert.AreEqual(valueForApproved, dbView.GetPropertyValue("Approved"));
        }
        
        [Test]  // Ensures that property setters in the code point to the correct property
        public void Test_PropertySettersUseCorrectPropertyNames()
        {
            CheckIfTestShouldBeIgnored();
            //---------------Set up test pack-------------------
            DBView dbView = new DBView();
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            object valueForDateCreated = TestUtilsShared.GetRandomDate();            
            dbView.SetPropertyValue("DateCreated", valueForDateCreated);
            object valueForOwner = TestUtilsShared.GetRandomString();            
            dbView.SetPropertyValue("Owner", valueForOwner);
            object valueForViewName = TestUtilsShared.GetRandomString(1,255);            
            dbView.SetPropertyValue("TableName", valueForViewName);
            object valueForSchemaName = TestUtilsShared.GetRandomString(1, 255);
            dbView.SetPropertyValue("SchemaName", valueForSchemaName);
            object valueForDatabaseID = TestUtilsDBDatabase.CreateSavedDBDatabase().DatabaseID;            
            dbView.SetPropertyValue("DatabaseID", valueForDatabaseID);
            object valueForTableType = TestUtilsShared.GetRandomString();            
            dbView.SetPropertyValue("TableType", valueForTableType);
            object valueForTableComment = TestUtilsShared.GetRandomString();            
            dbView.SetPropertyValue("TableComment", valueForTableComment);
            object valueForCreateTime = TestUtilsShared.GetRandomDate();            
            dbView.SetPropertyValue("CreateTime", valueForCreateTime);
            object valueForUpdateTime = TestUtilsShared.GetRandomDate();            
            dbView.SetPropertyValue("UpdateTime", valueForUpdateTime);
            
            object valueForApproved = TestUtilsShared.GetRandomBoolean();            
            dbView.SetPropertyValue("Approved", valueForApproved);
            
            //---------------Test Result -----------------------
            Assert.AreEqual(valueForDateCreated, dbView.DateCreated);
            Assert.AreEqual(valueForOwner, dbView.Owner);
            Assert.AreEqual(valueForViewName, dbView.TableName);
            Assert.AreEqual(valueForSchemaName, dbView.SchemaName);
            Assert.AreEqual(valueForDatabaseID, dbView.DatabaseID);
            Assert.AreEqual(valueForTableType, dbView.TableType);
            Assert.AreEqual(valueForTableComment, dbView.TableComment);
            Assert.AreEqual(valueForCreateTime, dbView.CreateTime);
            Assert.AreEqual(valueForUpdateTime, dbView.UpdateTime);
            Assert.AreEqual(valueForApproved, dbView.Approved);
        }
        
        [Test]  // Makes sure there are no non-null rules in the database that don't have corresponding compulsory rules
        public void Test_SetPropertyValue_Null()
        {
            CheckIfTestShouldBeIgnored();
            //---------------Set up test pack-------------------
            DBView dbView = TestUtilsDBView.CreateSavedDBView();
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            dbView.DateCreated = null;
            dbView.Owner = null;
            dbView.TableComment = null;
            dbView.CreateTime = null;
            dbView.UpdateTime = null;
//            dbView.PendingChangeType = null;
            dbView.Approved = null;
            dbView.Save();

            //---------------Test Result -----------------------
            BusinessObjectManager.Instance.ClearLoadedObjects();
            GC.Collect();
            TestUtilsDomain.WaitForGC();
            DBView retrievedDBView =
                Broker.GetBusinessObject<DBView>(dbView.ID);
            
            Assert.IsNull(retrievedDBView.DateCreated);
            Assert.IsNull(retrievedDBView.Owner);
            Assert.IsNull(retrievedDBView.TableComment);
            Assert.IsNull(retrievedDBView.CreateTime);
            Assert.IsNull(retrievedDBView.UpdateTime);
            Assert.IsNull(retrievedDBView.Approved);
        }

        [Test]
        public void Test_NotSettingCompulsoryPropertiesThrowsException()
        {
            CheckIfTestShouldBeIgnored();
            //---------------Set up test pack-------------------
            BORegistry.DataAccessor = new DataAccessorInMemory();
            DBView dbView = TestUtilsDBView.CreateUnsavedValidDBView();

            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            dbView.TableName = null;
            dbView.ViewID = null;
            dbView.DatabaseID = null;
            
            try
            {
                dbView.Save();
                Assert.Fail("Should throw an exception when compulsory properties are null");
            }
                //---------------Test Result -----------------------
            catch (BusObjectInAnInvalidStateException ex)
            {
                StringAssert.Contains("Table Name' is a compulsory field and has no value", ex.Message);
                StringAssert.Contains("ViewID' is a compulsory field and has no value", ex.Message);
                StringAssert.Contains("DatabaseID' is a compulsory field and has no value", ex.Message);
            }
        }
        
        [Test]  // Checks that the read-write rules have not been changed in the class defs
        public void Test_ReadWriteRules()
        {
            CheckIfTestShouldBeIgnored();
            //---------------Set up test pack-------------------
            ClassDef classDef = ClassDef.Get<DBView>();

            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            
            //---------------Test Result -----------------------
            Assert.AreEqual("ReadWrite",classDef.PropDefColIncludingInheritance["DateCreated"].ReadWriteRule.ToString());
            Assert.AreEqual("ReadWrite",classDef.PropDefColIncludingInheritance["Owner"].ReadWriteRule.ToString());
            Assert.AreEqual("ReadWrite",classDef.PropDefColIncludingInheritance["TableName"].ReadWriteRule.ToString());
            Assert.AreEqual("WriteNew",classDef.PropDefColIncludingInheritance["ViewID"].ReadWriteRule.ToString());
            Assert.AreEqual("WriteNew",classDef.PropDefColIncludingInheritance["DatabaseID"].ReadWriteRule.ToString());
            Assert.AreEqual("WriteOnce",classDef.PropDefColIncludingInheritance["TableType"].ReadWriteRule.ToString());
            Assert.AreEqual("ReadWrite",classDef.PropDefColIncludingInheritance["TableComment"].ReadWriteRule.ToString());
            Assert.AreEqual("ReadWrite",classDef.PropDefColIncludingInheritance["CreateTime"].ReadWriteRule.ToString());
            Assert.AreEqual("ReadWrite",classDef.PropDefColIncludingInheritance["UpdateTime"].ReadWriteRule.ToString());
            Assert.AreEqual("ReadWrite",classDef.PropDefColIncludingInheritance["PendingChangeType"].ReadWriteRule.ToString());
            Assert.AreEqual("ReadWrite",classDef.PropDefColIncludingInheritance["Approved"].ReadWriteRule.ToString());
        }
        
        
        
        
        [Test]  // Checks that classes using primary keys that are not an ID cannot have duplicate primary key values
        public void Test_NonIDPrimaryKey_ChecksForUniqueness()
        {
            CheckIfTestShouldBeIgnored();
            // Test does not apply to this class since the primary key is an ID
        }
        
        
        [Test]  // Checks that BOs in a single relationship load correctly (no tampering with class defs)
        public void Test_LoadThroughSingleRelationship_Database()
        {
            CheckIfTestShouldBeIgnored();
            //---------------Set up test pack-------------------
            BORegistry.DataAccessor = new DataAccessorInMemory();
            DBView dbView = TestUtilsDBView.CreateSavedDBView();

            IDBDatabase boForRelationshipDatabase = dbView.Database;

            BusinessObjectManager.Instance.ClearLoadedObjects();
            GC.Collect();
            TestUtilsDomain.WaitForGC();
            //---------------Execute Test ----------------------
            DBDatabase loadedRelatedBO = Broker.GetBusinessObject<DBDatabase>(boForRelationshipDatabase.ID);
            DBView loadedDBView = Broker.GetBusinessObject<DBView>(dbView.ID);
            //---------------Test Result -----------------------
            Assert.AreEqual(boForRelationshipDatabase, loadedDBView.Database);
            Assert.AreEqual(loadedRelatedBO, loadedDBView.Database);
            Assert.AreEqual(loadedRelatedBO, dbView.Database);
        }
  /*      [Test]  // Checks that BOs in a single relationship load correctly (no tampering with class defs)
        public void Test_LoadThroughSingleRelationship_MappedDMClass()
        {
            CheckIfTestShouldBeIgnored();
            //---------------Set up test pack-------------------
            BORegistry.DataAccessor = new DataAccessorInMemory();
            DBView dbView = TestUtilsDBView.CreateSavedDBView();

            FireStarterModeller.BO.DMClass boForRelationshipMappedDMClass = TestUtilsShared.CreateSavedDMClass();
            dbView.SetMappedDMClass(boForRelationshipMappedDMClass);
            dbView.Save();

            BusinessObjectManager.Instance.ClearLoadedObjects();
            GC.Collect();
            TestUtilsDomain.WaitForGC();
            //---------------Execute Test ----------------------
            FireStarterModeller.BO.DMClass loadedRelatedBO = Broker.GetBusinessObject<FireStarterModeller.BO.DMClass>(boForRelationshipMappedDMClass.ID);
            DBView loadedDBView = Broker.GetBusinessObject<DBView>(dbView.ID);
            //---------------Test Result -----------------------
            Assert.AreEqual(boForRelationshipMappedDMClass, loadedDBView.GetMappedDMClass());
            Assert.AreEqual(loadedRelatedBO, loadedDBView.GetMappedDMClass());
            Assert.AreEqual(loadedRelatedBO, dbView.GetMappedDMClass());
        }*/

        [Test]  // Checks that a related collection loads correctly (no tampering with class defs)
        public void Test_LoadThroughMultipleRelationship_Columns()
        {
            CheckIfTestShouldBeIgnored();
            //---------------Set up test pack-------------------
            BORegistry.DataAccessor = new DataAccessorInMemory();
            DBView dbView = TestUtilsDBView.CreateSavedDBView();

            DBViewColumn boForRelationshipColumns = TestUtilsDBViewColumn.CreateUnsavedValidDBColumn();
            boForRelationshipColumns.TableID = dbView.ViewID;
            boForRelationshipColumns.Save();

            BusinessObjectManager.Instance.ClearLoadedObjects();
            GC.Collect();
            TestUtilsDomain.WaitForGC();
            //---------------Assert Preconditions---------------
            Assert.AreEqual(1, dbView.Columns.Count);
            //---------------Execute Test ----------------------
            DBViewColumn loadedRelatedBO = Broker.GetBusinessObject<DBViewColumn>(boForRelationshipColumns.ID);
            DBView loadedDBView = Broker.GetBusinessObject<DBView>(dbView.ID);
            //---------------Test Result -----------------------
            Assert.AreEqual(1, loadedDBView.Columns.Count);
            Assert.AreEqual(boForRelationshipColumns, loadedDBView.Columns[0]);
            Assert.AreEqual(loadedRelatedBO, loadedDBView.Columns[0]);
            Assert.AreEqual(loadedRelatedBO, dbView.Columns[0]);
        }
 
        // ReSharper restore RedundantNameQualifier
    }
}